home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / pas / swag / faq.swg / 0001_General PASCAL FAQ.pas next >
Pascal/Delphi Source File  |  1993-05-28  |  38KB  |  774 lines

  1.         ANSWERS TO FREQUENTLY ASKED PASCAL QUESTIONS
  2.         ============================================
  3.  
  4. 1...
  5.                                                                               
  6.   Q. How do I pass an error level code when my program finishes?              
  7.                                                                               
  8.   A. The halt procedure takes an optional parameter of type word. Thus -      
  9.                                                                               
  10.          halt(1);                                                             
  11.                                                                               
  12.      terminates the program with an errorlevel of 1.  If halt is used without 
  13.      a parameter it is the same as -                                          
  14.                                                                               
  15.          halt(0);                                                             
  16.                                                                               
  17.      Note:  When a program is terminated using the halt procedure any exit    
  18.             procedure that has previously been set up is executed.            
  19.  
  20.  
  21. 2...
  22.                                                                           
  23.   Q. How do I empty the keyboard buffer?                                      
  24.                                                                               
  25.   A. There are several ways that this can be achieved.  However the safest    
  26.      is -                                                                     
  27.                                                                               
  28.         while Keypressed do ch := ReadKey;                                    
  29.                                                                               
  30.      This requires that a variable ch of type char is declared and the crt    
  31.      unit be used.  To do it without using a variable -                       
  32.                                                                               
  33.        while Keypressed do while ReadKey = #0 do;                             
  34.                                                                               
  35.      or if using TP6 with extended syntax enabled -                           
  36.                                                                               
  37.         while KeyPressed do ReadKey;                                          
  38.                                                                               
  39.      If you do not wish to incur the substantial overhead involved with the   
  40.      use of the CRT unit and there is no requirement for the program to run   
  41.      under a multi-tasker -                                                   
  42.                                                                               
  43.         var                                                                   
  44.           head : byte absolute $40:$1c;                                       
  45.           tail : byte absolute $40:$1e;                                       
  46.                                                                               
  47.         tail := head;                                                         
  48.  
  49. 3...
  50.  
  51.   Q. When I redirect the screen output of my programs to a file the file is   
  52.      empty and the output still appears on the screen. What am I doing        
  53.      wrong?                                                                   
  54.                                                                               
  55.   A. You are probably using the CRT unit and its default method of writing    
  56.      to stdout is by direct screen writes.  In order to enable output to be   
  57.      redirected all writes must be done by DOS.  Setting the variable         
  58.      DirectVideo to false has no effect on redirection as all it does is use  
  59.      the BIOS for screen writes - not DOS.                                    
  60.                                                                               
  61.      To enable redirection you must not use the CRT unit                      
  62.                                                                               
  63.      OR                                                                       
  64.                                                                               
  65.      assign(output,'');                                                       
  66.      rewrite(output);                                                         
  67.                                                                               
  68.      This will make all output go through DOS and thus can be redirected if   
  69.      desired.  To restore the default situation -                             
  70.                                                                               
  71.      AssignCRT(output); rewrite(output);                                      
  72.  
  73.  
  74. 4...
  75.  
  76.    Q. How do I make a string that is lower or mixed case all uppercase?
  77.                                                                               
  78.    A. There are several ways to convert lower case characters to upper case.  
  79.       Here are some of them.                                                  
  80.                                                                               
  81.       As a procedure (excluding asm code this is the fastest way)             
  82.                                                                               
  83.         procedure StrUpper(var st: string);                                   
  84.           var x : byte;                                                       
  85.           begin                                                               
  86.             for x := 1 to length(st) do                                       
  87.               st[x] := UpCase(st[x]);                                         
  88.           end;                                                                
  89.                                                                               
  90.       As a function (slower but sometimes more convenient) -                  
  91.                                                                               
  92.         function StrUpper(st: string): string;                                
  93.           var x : byte;                                                       
  94.           begin                                                               
  95.             StrUpper[0] := st[0];                                             
  96.             for x := 1 to length(st) do                                       
  97.               StrUpper[x] := UpCase(st[x]);                                   
  98.           end;                                                                
  99.                                                                               
  100.       Both the above are suitable for the English language .  However from    
  101.       version 4.0 onwards, DOS has had the facility to do this in a way that  
  102.       is country (language) specific.  I am indebted to Norbert Igl for the   
  103.       basic routine.  I have modified his code slightly.  For the anti-goto   
  104.       purists this is a good example of a goto that is convenient, efficient, 
  105.       self-documenting and structured.  The dos calls would make this method  
  106.       the slowest of all.                                                     
  107.                                                                               
  108.      function StrUpper(s: string): string;                                    
  109.        { Country specific string-to-uppercase conversion. Requires DOS unit } 
  110.        label                                                                  
  111.          fail;                                                                
  112.        var                                                                    
  113.          regs : registers;                                                    
  114.          x    : byte;                                                         
  115.        begin                                                                  
  116.          if lo(DosVersion) >= 4 then begin                                    
  117.            with regs do begin                                                 
  118.              ax := $6521;                                                     
  119.              ds := seg(s);                                                    
  120.              dx := ofs(s[1]);                                                 
  121.              cx := length(s);                                                 
  122.              msdos(regs);                                                     
  123.              if odd(flags) then { the attempted conversion failed so }        
  124.                goto fail;                                                     
  125.            end; { with }                                                      
  126.          end { if DOS >= 4.0 } else                                           
  127.        fail:                                                                  
  128.            for x := 1 to length(s) do                                         
  129.              s[x] := UpCase(s[x]);                                            
  130.          StrUpper := s;                                                       
  131.        end; { StrUpper }                                                      
  132.  
  133.  
  134.  
  135. 5...
  136.                                                                               
  137.    Q. When I include ANSI codes in a string and write that string to the      
  138.       screen the actual codes appear on the screen, rather than the results   
  139.       they are supposed to achieve.                                           
  140.                                                                               
  141.    A. In order for ANSI codes to be interpreted, screen writes must be        
  142.       directed through DOS and there must have been a suitable driver loaded  
  143.       via the config.sys file at boot time.  All output can be directed       
  144.       through DOS and the driver by -                                         
  145.                                                                               
  146.       Not using the crt unit                                                  
  147.                                                                               
  148.       OR -                                                                    
  149.                                                                               
  150.       assign(output,'');                                                      
  151.       rewrite(output);                                                        
  152.                                                                               
  153.       in which case ALL screen writes are "ANSI code sensitive"               
  154.                                                                               
  155.       OR -                                                                    
  156.                                                                               
  157.       You can set up write procedures that will be "ANSI code sensitive".     
  158.       (You will need an initialisation procedure to set this up.)             
  159.                                                                               
  160.       var                                                                     
  161.         ansi : text;                                                          
  162.                                                                               
  163.       procedure AssignANSI(var ansifile : text);                              
  164.         begin                                                                 
  165.           assign(ansifile,'CON');                                             
  166.           rewrite(ansifile);                                                  
  167.         end; { AssignANSI }                                                   
  168.                                                                               
  169.       procedure WriteANSI(var st: string);                                    
  170.         begin                                                                 
  171.           write(ansi,st)                                                      
  172.         end; { WriteANSI }                                                    
  173.                                                                               
  174.       procedure WriteLnANSI(var st: string);                                  
  175.         begin                                                                 
  176.           writeANSI(st);                                                      
  177.           writeln(ansi);                                                      
  178.         end; { WriteANSI }                                                    
  179.                                                                               
  180.       ObviousLy, if the ANSI.SYS driver (or an equivalent) is not installed   
  181.       none of the above can work.                                             
  182.                                                                               
  183.       Setting the variable DirectVideo in the CRT unit to false will not      
  184.       achieve the desired result as this merely turns off direct screen       
  185.       writes and uses the BIOS for all screen output.                         
  186.  
  187.  
  188. 6...
  189.                                                                               
  190.    Q. When I try to shell to DOS nothing happens. What am I doing wrong?      
  191.                                                                               
  192.    A. In order to be able to execute any child process there must be          
  193.       sufficient memory available for it to load and execute.  Unless you     
  194.       advise differently at compile time, a Turbo Pascal program grabs all    
  195.       available memory for itself when it is loaded.  To reserve memory for a 
  196.       child process use the compiler memory directive -                       
  197.                                                                               
  198.         {$M 16384,0,0)                                                        
  199.       the default is -                                                        
  200.         {$M 16384,0,655360}                                                   
  201.                                                                               
  202.       The first figure - StackMin - is the amount of memory to be allocated   
  203.       for the stack:                                                          
  204.                                                                               
  205.       Minimum is:    1024                                                     
  206.       Default is:   16384                                                     
  207.       Maximum is:   65520                                                     
  208.                                                                               
  209.       The next figure - HeapMin -is the minumum amount of memory to be        
  210.       allocated for the heap. If there is less memory available than this     
  211.       figure the program will not load.                                       
  212.                                                                               
  213.       Minimum is:          0                                                  
  214.       Default is:          0                                                  
  215.       Maximum is:     655360  In practice it will be the amount of free       
  216.                               memory less the space required for the stack,   
  217.                               less the code space of the program.  You should 
  218.                               set this to 0 unless your program uses the      
  219.                               heap.  In that case, set it to the lowest       
  220.                               possible figure to prevent heap allocation      
  221.                               errors.  In most cases it is best to leave it   
  222.                               at zero and do error checking within the        
  223.                               program for sufficient memory at allocation     
  224.                               time.                                           
  225.                                                                               
  226.       The last figure is the crucial on as regards child processes.  It       
  227.       should always be low enough to leave memory left over for a child       
  228.       process and high enough not to cause problems for the program when      
  229.       allocating heap memory.                                                 
  230.                                                                               
  231.       Minimum is:  HeapMin                                                    
  232.       Default is:  655360                                                     
  233.       Maximum is:  655360     If less than the requested amount is available  
  234.                               no error is reorted.  Instead all available     
  235.                               memory is allocated for heap use.               
  236.  
  237.  
  238.  
  239. 7...
  240.                                                                               
  241.    Q. How do I shell to DOS?                                                  
  242.                                                                               
  243.    A. SwapVectors;                                                            
  244.       exec(GetEnv('COMSPEC','');                                              
  245.       SwapVectors;                                                            
  246.                                                                               
  247.       Read previous section on memory allocation.                             
  248.                                                                               
  249.       I find that it is a good idea to write my own Exec function which will  
  250.       do everything that is needed for me.  I have it return an integer value 
  251.       that is the DosError code.                                              
  252.                                                                               
  253.       function Exec(p1,p2: string);                                           
  254.         begin                                                                 
  255.           SwapVectors;                                                        
  256.           Dos.Exec(p1,p2);                                                    
  257.           SwapVectors;                                                        
  258.           Exec := DosError;                                                   
  259.         end;                                                                  
  260.                                                                               
  261.       This enables me to have a statement such as -                           
  262.                                                                               
  263.       ReportError(Exec(GetEnv('COMPSEC'),''));                                
  264.                                                                               
  265.       Now you can have an empty ReportError procedure or you can make it      
  266.       report the error - whatever is suitable for you application.            
  267.  
  268.  
  269. 8...
  270.                                                                               
  271.    Q. When I execute a child process redirection does not work. Why?          
  272.                                                                               
  273.    A. Redirection of a child process's output only works if it is run under   
  274.       another copy of the command processor.  So -                            
  275.                                                                               
  276.       exec('YourProg.exe',' > nul');    will not work but                     
  277.       exec(GetEnv('COMSPEC'),'/c YourProg > nul'); will work.                 
  278.  
  279.  
  280. 9...
  281.  
  282.    Q. How do I read an errorlevel from a child process?
  283.  
  284.    A. After executing a child process the errorlevel returned can be read
  285.       by calling the DosExitCode function which returns a word.  The low
  286.       byte is the errorlevel.  A full description is in the manual.
  287.  
  288.       If the command interpreter is the child process and it in turn
  289.       executes a child process then the errorlevel of the second child
  290.       process cannot be read without resorting to some trickery.
  291.  
  292.  
  293. 10...
  294.  
  295.    Q. When I read a text file that has lines exceeding 255 characters I
  296.       lose all those characters from the 256th one on each time there is a
  297.       line that exceeds that length.  How can I prevent this?
  298.  
  299.    A. Turbo Pascal's readln procedure reads a line up to the 255th
  300.       character then skips to the next line.  To get around this you
  301.       should declare a buffer at least as large as the longest possible
  302.       line and then use the read procedure.  The best size for the buffer
  303.       is a multiple of 2048 bytes.
  304.  
  305.       const
  306.         BufferSize = 2048;
  307.         LineLength = 78;
  308.       type
  309.         textbuffer = array[1..BufferSize] of char;
  310.       var
  311.         st          : string;
  312.         f           : text;
  313.         buffer      : textbuffer;
  314.  
  315.       function ReadTxtLn(var tf: text; var s: string; max: byte): integer;
  316.         { Reads a string of a maximum length from a text file }
  317.         var
  318.           len         : byte absolute s;
  319.         begin
  320.           len := 0;
  321.           {$I-}
  322.           while (len < max) and not eoln(tf) do begin
  323.             inc(len);
  324.             read(tf);
  325.           end;
  326.           if eoln(tf) then
  327.             readln(tf);
  328.           ReadTxtLn := IOResult;
  329.           {$I+}
  330.         end; { ReadTxtLn }
  331.  
  332.       begin
  333.         assign(f,filename);
  334.         reset(f);
  335.         SetTextBuf(f,buffer);
  336.         while not eof(f) and (ReadTxtLn(f,st,LineLength) = 0) do
  337.           writeln(st);
  338.         close(f);
  339.       end.
  340.  
  341.  
  342. 11...
  343.  
  344.    Q. How do I convert nul terminated asciiz strings to Turbo Pascal
  345.       strings?
  346.  
  347.    A. Here is a function that will do that -
  348.  
  349.       function Asc2Str(var s; max: byte): string;
  350.         { Converts an ASCIIZ string to a Turbo Pascal string }
  351.         { with a maximum length of max.                      }
  352.         var starray  : array[1..255] of char absolute s;
  353.             len      : integer;
  354.         begin
  355.           len        := pos(#0,starray)-1;              { Get the length }
  356.           if (len > max) or (len < 0) then      { length exceeds maximum }
  357.             len      := max;                         { so set to maximum }
  358.           Asc2Str    := starray;
  359.           Asc2Str[0] := chr(len);                           { Set length }
  360.         end;  { Asc2Str }
  361.  
  362.  
  363. 12...
  364.  
  365.    Q. How can I tell if a particular bit of a variable is set or not? How can
  366.       I set it?  How can I turn it off? How can I make a large bit map and
  367.       then determine if a particular bit - say bit 10000 is on/of?
  368.  
  369.    A. This question, or a variation of it, is one of the most commonly asked
  370.       questions in the echo and there are several ways of doing what is
  371.       wanted.  None are necessarily right or wrong.  The way I will describe
  372.       is designed to take up as little code/data space as possible.  I do not
  373.       attempt to explain the theory behind these functions as this can be
  374.       obtained from any good book. Question 16 also contains valuable extra
  375.       help on the subject of truth tables.
  376.  
  377.       The use of sets can be the best bit manipulation method if you have
  378.       control over the data being used. Here is an example of a byte variable
  379.       for a BBS program which sets various user access level flags.
  380.  
  381.          Bit 0 = Registered User
  382.              1 = Twit
  383.              2 = Normal
  384.              3 = Extra
  385.              4 = Privileged
  386.              5 = Visiting Sysop
  387.              6 = Assistant Sysop
  388.              7 = Sysop
  389.  
  390.        type
  391.          status_type  = (Registered,
  392.                          Twit,
  393.                          Normal,
  394.                          Extra,
  395.                          Privileged,
  396.                          VisitingSysop,
  397.                          AssistantSysop,
  398.                          Sysop);
  399.           status_level = set of status_type;
  400.  
  401.        var
  402.          access_flags  : status_level;
  403.  
  404.       Let us assume you have someone who logs on and you wish to determine
  405.       his user access level.  After reading access_flags from the user data
  406.       file -
  407.  
  408.            if Sysop in access_flags then ....
  409.  
  410.       To set the sysop flag -
  411.  
  412.            access_flags := access_flags + [Sysop];
  413.  
  414.       To reset the sysop flag -
  415.  
  416.            access_flags := access_flags - [Sysop];
  417.  
  418.       However on many occasions using a set may not be a suitable method.
  419.       You may simply need to know if bit 5 is set or not.  Here is the method
  420.       that I consider the best -
  421.  
  422.         function BitIsSet(var V,  bit: byte): boolean;
  423.           begin
  424.             BitIsSet := odd(V shr bit);
  425.           end;
  426.  
  427.       To set a bit -
  428.  
  429.          procedure SetBit(var V: byte; bit: byte);
  430.            begin
  431.              V := V or (1 shl bit);
  432.            end;
  433.  
  434.       To reset a bit -
  435.  
  436.          procedure ResetBit(var V: byte; bit: byte);
  437.            begin
  438.              V := V and not(1 shl bit);
  439.            end;
  440.  
  441.       To toggle (flip) a bit -
  442.  
  443.          procedure ToggleBit(var V: byte; bit: byte);
  444.            begin
  445.              V := V xor (1 shl bit);
  446.            end;
  447.  
  448.       Now a bit map can be made up from an array of bytes.  If stored on the
  449.       heap you can test any bit up to number 524159 (zero based).  Here's
  450.       how.
  451.  
  452.       type
  453.         map = array[0..maxsize] of byte;
  454.         { set maxsize to number of bits div 8 -1 needed in the bit map }
  455.  
  456.       function BitSetInBitMap(var x; numb : longint): boolean;
  457.         { Tests the numb bit in the bitmap array }
  458.         var m: map absolute x;
  459.         begin
  460.           BitSetInBitMap := odd(m[numb shr 3] shr (numb and 7));
  461.         end;
  462.  
  463.       procedure SetBitInBitMap(var x; numb: word);
  464.         { Sets the numb bit in the bitmap array }
  465.         var m: map absolute x;
  466.         begin
  467.           m[numb shr 3] := m[numb shr 3] or (1 shl (numb and 7))
  468.         end;
  469.  
  470.       procedure ResetBitInBitMap(var x; numb : longint);
  471.         { Resets the numb bit in the bitmap array }
  472.         var m: map absolute x;
  473.         begin
  474.          m[numb shr 3] := m[numb shr 3] and not(1 shl (numb and 7));
  475.         end;
  476.  
  477.       procedure ToggleBitInBitMap(var x; numb : longint);
  478.         { Toggles (flips) the numb bit in the bitmap array }
  479.         var m: map absolute x;
  480.         begin
  481.           m[numb shr 3] := m[numb shr 3] xor (1 shl (numb and 7));
  482.         end;
  483.  
  484.  
  485. 13...
  486.  
  487.    Q. How can I find a particular string in any file - text or binary?
  488.  
  489.    A. The Boyer-Moore string search algorithm is considered to be the fastest
  490.       method available.  However in a rare worst-case scenario it can be
  491.       slightly slower than a linear brute-force method.  The following
  492.       demonstration program will show how it works and could easily be
  493.       modified to allow for command line paramters etc.
  494.  
  495.  
  496.       program BMSearchDemo;
  497.  
  498.       type
  499.         bigarray = array[0..32767] of byte;
  500.         baptr    = ^bigarray;
  501.         BMTable  = array[0..255] of byte;
  502.  
  503.       const
  504.         KeyStr : string = 'Put whatever you want found here';
  505.         fname  : string = 'f:\Filename.txt';
  506.  
  507.       var
  508.         Btable : BMtable;
  509.         buffer : baptr;
  510.         f      : file;
  511.         result,
  512.         position : word;
  513.         offset : longint;
  514.         finished,
  515.         Strfound  : boolean;
  516.  
  517.       procedure MakeBMTable(var t : BMtable; var s);
  518.         { Makes a Boyer-Moore search table. s = the search string t = the table }
  519.         var
  520.           st  : BMtable absolute s;
  521.           slen: byte absolute s;
  522.           x   : byte;
  523.         begin
  524.           FillChar(t,sizeof(t),slen);
  525.           for x := slen downto 1 do
  526.             if (t[st[x]] = slen) then
  527.               t[st[x]] := slen - x
  528.         end;
  529.  
  530.       function BMSearch(var buff,st; size : word): word;
  531.         { Not quite a standard Boyer-Moore algorithm search routine }
  532.         { To use:  pass buff as a dereferenced pointer to the buffer}
  533.         {          st is the string being searched for              }
  534.         {          size is the size of the buffer                   }
  535.         { If st is not found, returns $ffff                         }
  536.         var
  537.           buffer : bigarray absolute buff;
  538.           s      : array[0..255] of byte absolute st;
  539.           len    : byte absolute st;
  540.           s1     : string absolute st;
  541.           s2     : string;
  542.           count,
  543.           x      : word;
  544.           found  : boolean;
  545.         begin
  546.           s2[0] := chr(len);       { sets the length to that of the search string }
  547.           found := false;
  548.           count := pred(len);
  549.           while (not found) and (count < (size - len)) do begin
  550.             if (buffer[count] = s[len]) then { there is a partial match } begin
  551.               if buffer[count-pred(len)] = s[1] then { less partial! } begin
  552.                 move(buffer[count-pred(len)],s2[1],len);
  553.                 found := s1 = s2;                   { if = it is a complete match }
  554.                 BMSearch := count - pred(len);      { will stick unless not found }
  555.               end;
  556.               inc(count);                { bump by one char - match is irrelevant }
  557.             end
  558.             else
  559.               inc(count,Btable[buffer[count]]);   { no match so increment maximum }
  560.           end;
  561.           if not found then
  562.             BMSearch := $ffff;
  563.         end;  { BMSearch }
  564.  
  565.  
  566.       begin
  567.         new(buffer);
  568.         assign(f,fname);
  569.         reset(f,1);
  570.         offset := 0;
  571.         MakeBMTable(Btable,KeyStr);
  572.         repeat
  573.           BlockRead(f,buffer^,sizeof(buffer^),result);
  574.           position := BMSearch(buffer^,KeyStr,result);
  575.           finished := (result < sizeof(buffer^)) or (position <> $ffff);
  576.           if position = $ffff then
  577.             inc(offset,result);
  578.           Strfound := position <> $ffff;
  579.         until finished;
  580.         close(f);
  581.         if Strfound then
  582.           writeln('Found at offset ',offset)
  583.         else
  584.           writeln('Not found');
  585.       end.
  586.  
  587. 14...
  588.  
  589.    Q. How can I put a apostrophe in a string?
  590.  
  591.    A. Just put in extra apostrophes.  If you want st to be equal to the
  592.       string -
  593.         The word 'quoted' is in quotes
  594.       do this -
  595.         st := 'The word ''quoted'' is in quotes';
  596.  
  597.       if you want the following to be written to screen -
  598.         'This is a quoted string'
  599.       do this -
  600.         writeln('''This is a quoted string''');
  601.  
  602.  
  603. 15...
  604.  
  605.    Q. What are the best books to purchase to help me learn Turbo Pascal?
  606.  
  607.    A. There are many good books for learners.  Here are a few -
  608.  
  609.       Complete Turbo Pascal - Third Edition - Jeff Duntemann
  610.       Mastering Turbo Pascal 6 - Tom Swann
  611.       Turbo Pascal - The Complete Reference - O'Brien.
  612.  
  613.       For advanced users there are also many good books.  Here are a few
  614.       that I have found useful - (Those marked with an asterisk are not
  615.       purely for Turbo Pascal)
  616.  
  617.       Turbo Pascal 6 - Techniques and Utilities - Rubenking
  618.       Turbo Pascal Internals - Tischer
  619.       * PC System Programming for Developers - Tischer
  620.       * Undocumented DOS - Schulman
  621.  
  622.       Any learner would be well advised to obtain a well known library
  623.       such as Technojock's Turbo Toolkit (TTT) which is shareware and
  624.       study the source code.
  625.  
  626.  16.
  627.  
  628.    Q. hat are "truth tables" and how do they work?
  629.  
  630.    A. Truth tables are a set of rules that are used to determine the result of
  631.       logical operations.  The logical operators are -
  632.  
  633.         NOT
  634.         AND
  635.         OR
  636.         XOR.
  637.  
  638.       Here is a brief explanation of truth tables.  When two values are
  639.       logically compared by using a logical operator each bit of one value is
  640.       directly compared to the corresponding bit in the other value and the
  641.       same bit in the returned value is set or reset according to the
  642.       following truth table.
  643.  
  644.              NOT         AND             OR            XOR
  645.          not 1 = 0    0 and 0 = 0    0 or 0 = 0    0 xor 0 = 0
  646.          not 0 = 1    0 and 1 = 0    0 or 1 = 1    0 xor 1 = 1
  647.                       1 and 0 = 0    1 or 0 = 1    1 xor 0 = 1
  648.                       1 and 1 = 1    1 or 1 = 1    1 xor 1 = 0
  649.  
  650.       NOT reverses the bit.
  651.       AND sets the returned bit if both compared bits are set.
  652.       OR  sets the returned bit if either of the compared bits are set.
  653.       XOR sets the returned bit if the compared bits are not the same.
  654.  
  655.  
  656.  17.
  657.  
  658.    Q. What are pointers and how can I use them?  I have heard that they are
  659.       variables that can be created and discarded as required thus saving
  660.       memory.  Is this true?
  661.  
  662.    A. A pointer is a variable that contains a memory address.
  663.  
  664.       The heap is all of that memory allocated by DOS to a program for its
  665.       use that has not been used by the program for its code, global data or
  666.       stack.
  667.  
  668.       Dynamic variables are variables that have had space allocated for them
  669.       on the heap.
  670.  
  671.       Dynamic variables have no identifier (are unnamed).  Because of this
  672.       they need an associated variable that can be used to find where they
  673.       reside in memory. Pointers are ideal for this but need some method to
  674.       define what type of data it is that they are pointing at.  Pascal
  675.       provides this method.
  676.  
  677.         type
  678.           Str10Ptr = ^string[10];
  679.           { This means Str10Ptr is a pointer that points to data of type }
  680.           { string[10].                                                  }
  681.         var
  682.           S : Str10Ptr;
  683.  
  684.       In the above example S is a pointer that has been defined as pointing
  685.       to an address in memory that will contain (or should contain) data of
  686.       type string[10].
  687.  
  688.       However how does S get this value?  How does it know where that data's
  689.       address is supposed to be?  Well until the programmer allocates memory
  690.       for that data S's value is undefined, so it could be literally
  691.       pointing anywhere. So it is *vital* that before we try to use it to
  692.       use/assign data from/to that memory location we give S a memory
  693.       address that is not being used for any other purpose at the moment and
  694.       that is big enough to hold the data that we want to place into it - in
  695.       this case at least 11 bytes.  We do this by -
  696.  
  697.         new(S);
  698.  
  699.       Pascal has now allocated at least 11 bytes of heap and has allocated S
  700.       with the address of the FIRST byte of that allocation.
  701.  
  702.       Ok... so far so good! How do we access that data (remembering that it
  703.       has no name).  Well we "dereference" the pointer. This is done by
  704.       placing a carat sign immediately following the pointer's identifier.
  705.  
  706.         S^ := 'Joe Bloggs';
  707.  
  708.       This statement actually means "Place the string 'Joe Bloggs' into the
  709.       memory address that S contains". This is referred to as "derferencing"
  710.       the pointer S.
  711.  
  712.       To "reference" a dynamic variable we "dereference" its associated
  713.       pointer variable.  We cannot say -
  714.  
  715.         S := 'Joe Bloggs';
  716.  
  717.       because S is a pointer and that would be trying to give a pointer a
  718.       string type value - a compiler "type mismatch" would occur. So every
  719.       time we wish to access that dynamic variable we dereference it.
  720.  
  721.       To delete the dynamic variable once it is of no further use is just a
  722.       matter of -
  723.  
  724.         dispose(S);
  725.  
  726.       What this statement does is release the memory previously used by S^
  727.       and make it available to be used for other purposes by the program.
  728.       Depending on the version of Pascal you are using it may not erase or
  729.       alter the contents of that memory and it may not give S a new value.
  730.       However any attempt to dereference S is an error as the integrity of
  731.       that memory location has been lost - it may have been allocated to
  732.       other data.
  733.  
  734.       Pointers do not *have* to point to a memory location in the heap or
  735.       even have their value always allocated by using the New procedure. Any
  736.       valid memory address can be assigned to them and then they can be
  737.       dereferenced as shown above.  As a simple example of this lets say you
  738.       want to examine the contents of the 16 byte area at $40:$f0 (the ICA
  739.       area). You could - (TP specific)
  740.  
  741.          type
  742.            ICA_Ptr = ^array[0..15] of byte;
  743.          var
  744.            B       : byte;
  745.            ICA     : ICA_Ptr;
  746.  
  747.           ICA := ptr($40,$f0);
  748.  
  749.       Now ICA points to the address specified and you can dereference it -
  750.  
  751.           B := ICA^[10];
  752.  
  753.       Hope that helps get you started into the complex world of memory
  754.       management and manipulation using pointers.  There are countless
  755.       permutations and methods that can be used.
  756.  
  757.  
  758.  18.
  759.  
  760.    Q. How do I do word wrap?
  761.  
  762.    A. The demo program WRAP.PAS in this archive demonstrates both word wrap
  763.       and the justifying of text.
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772.  
  773.  
  774.